#include "catch.hpp"
#include <fstream>
#include <bencoding.h>

using namespace std;
using namespace tiny_bt;

const char* torrent_file_name = "ubuntu-16.04.1-desktop-i386.iso.torrent";
const char* new_file_name = "new.torrent";

bool cmp_file(std::istream& l, std::istream& r)
{
	l.seekg(0, l.end);
	auto len_l = l.tellg();

	r.seekg(0, r.end);
	auto len_r = r.tellg();

	if (len_l != len_r)
	{
		return false;
	}

	l.seekg(0, l.beg);
	r.seekg(0, r.beg);

	const decltype(len_l) buf_len = 1024 * 64;

	std::unique_ptr<char[]> bl = std::make_unique<char[]>(static_cast<size_t>(buf_len));
	std::unique_ptr<char[]> rl = std::make_unique<char[]>(static_cast<size_t>(buf_len));

	auto count = len_l / buf_len;
	auto left = len_l % buf_len;

	for (decltype(count) i = 0; i < count; i++)
	{
		l.read(bl.get(), buf_len);
		r.read(rl.get(), buf_len);
		if (!l.good() || !r.good())
		{
			return false;
		}

		if (memcmp(bl.get(), rl.get(), static_cast<size_t>(buf_len)) != 0)
		{
			return false;
		}
	}

	if (left)
	{
		l.read(bl.get(), left);
		r.read(rl.get(), left);
		if (!l.good() || !r.good())
		{
			return false;
		}

		if (memcmp(bl.get(), rl.get(), static_cast<size_t>(left)) != 0)
		{
			return false;
		}
		
	}

	return true;
}

TEST_CASE("bencoding", "[bc]")
{
	{
		std::ifstream torrent_file;
		torrent_file.open(torrent_file_name, ios_base::in | ios_base::binary);
		REQUIRE((torrent_file.is_open() && torrent_file.good()));
		p_value b = b_reader().parse(torrent_file);

		std::fstream new_file;
		new_file.open(new_file_name, ios_base::binary | ios_base::out | ios_base::in | ios_base::trunc);
		REQUIRE((new_file.is_open() && new_file.good()));
		b_writer().write(b, new_file);

		REQUIRE(cmp_file(torrent_file, new_file));
	}
	CHECK(remove(new_file_name) == 0);
}
